#!/usr/local/bin/ruby
#
#  Copyright (c) 2009 Mu Dynamics, Inc. All rights reserved.

require 'rubygems'
require 'libxml'
require 'ddt_api'
require 'mu_api'
require 'netconfig'
# require 'spawn/lib/spawn'  # uncomment to use spawn

include LibXML
# include Spawn   # uncomment to use spawn

class Run < ActiveRecord::Base
  validates_presence_of :mu_ip, :host_names, :host_roles, :host_types,
    :scenario_name, :scenario_uuid, :testsuite_name, :testsuite_uuid
  has_many :results

  $select_one = " Select One ..."

  # from $mu_ip, get hosts, scenarios, and test suite names and uuids
  # and store them in hashmaps
  def self.populate(mu_ip=ENV['MU_IP'])
    $mu_ip = mu_ip.strip
    logger.debug "run.populate called with #{$mu_ip}"

    logger.debug "get scenarios"
    $scenarios = self.get_map("Scenario")
    $scenarios["#{$select_one}"] = ""

    logger.debug "get test sets"
    $testsuites = self.get_map("DDTSet")
    $testsuites["#{$select_one}"] = ""

    # get available endpoints (hosts and interfaces)
    @net = Netconfig.new($mu_ip)
    hosts = @net.get("hosts")
    interfaces = @net.get("interfaces")

    $host_names = Array.new
    $host_names << $select_one
    hosts['hosts'].each do | h |
       $host_names << h['name']
    end

    interfaces['interfaces'].each do | h |
       $host_names << h['name']
    end

  end

  def self.get_map(type="Scenario")
    # request the template information from the Mu

    map = Hash.new
    mu_api = Mu_Api.new($mu_ip, "/rai/rest/mu")
    result = mu_api.request("findUsing?type=#{type}")

    # get the uuids and names from the response
    uuids = []
    names = []
    result.find("//result").each do | t |
        uuids << t.attributes['uuid'] unless t.attributes['uuid'] == "" or t.attributes['uuid'].nil?
    end

    result.find("//name").each do | n |
      names << n.content unless n.content == "" or n.content.nil?
    end

    names.each do | n |
      logger.debug n
    end

    # map the names and uuids
    names.size.times do | idx |
      map[names[idx]] = uuids[idx]
    end

    return map
  end

  def self.mu_ip
    return $mu_ip
  end

  def self.scenarios
    return $scenarios
  end

  def self.host_names
    return $host_names
  end

  def self.host_roles
    return $host_roles
  end

  def self.testsuites
    return $testsuites
  end

  def self.clear_templates
    $host_names = nil
    $host_roles = nil
    $scenarios = nil
    $testsuites = nil
  end

  def get_run(run_id)
     r = []
     rows = ActiveRecord::Base.connection.execute("select * from runs where id='#{run_id}'")
     rows.each_hash{ |res| r << res }
     return r[0]
  end

  # get the run parameters from the db and pass them along to the run_test method
  def execute(run_id)
     r = []
     rows = ActiveRecord::Base.connection.execute("select * from runs where id='#{run_id}'")
     rows.each_hash{ |res| r << res }
     r.each do | rr |
       run_test(rr)
     end
   end

   # non-blocking call that spawns a thread to execute the test suite and post the results to the db
   #  for a simpler blocking implementation,
   #     just remove the 'spawn do' line, its corresponding 'end', and the spawn require at the top of this file
   def run_test(run)
   #  spawn(:method => :thread) do  # uncomment to use spawn
      @run_id = run['id']
      logger.debug "starting test run #{@run_id}"

      # set up the session and network configuration
      if $mu_ip.nil?
        $mu_ip = ENV['MU_IP']
      end

      # initializes a new DdtApi object and set up the session and network configuration
      @api = DdtApi.new($mu_ip)
      @api.new_session
      @api.load_scenario(run['scenario_uuid'])

      names = run['host_names'].split(",")
      roles = run['host_roles'].split(",")

      names.each do | n |
        logger.debug  "run_test: host names = #{n}"
      end

      roles.each do | r |
        logger.debug  "run_test: host roles = #{r}"
       end

      @api.set_hosts(roles, names)
      @api.setup_test

      # execute the test suite
      @api.run_test_suite(run['testsuite_uuid'])
      sleep 3
      results, failed, errors = @api.collect_results
      results.each do | r |
         options = " "
         name = r["testName"].to_s
         passed = r["testResult"].to_s
         message = r["testError"].to_s
         if message == ""
           message = " "
         end

         if !passed.include?("END")
           options_array = r["testOptions"]["options"]
           if !options_array.nil?
             options_array.each do | o |
               $DEBUG and puts o
               thing = "#{o["name"]} = #{o["value"]}\n"
               options = options + thing
             end
           end
         end

         # for each result ... add it
         unless passed.include?("END")
             created_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
             stmt = "INSERT INTO results (run_id, name, options,  passed, message, created_at, updated_at)
                                values (#{@run_id}, '#{name}', '#{options}', '#{passed}', '#{message}', '#{created_at}', '#{created_at}')"
             ActiveRecord::Base.connection.execute(stmt)
         end
      end   # end results.each
      stmt = "update runs set status='finished' where id='#{@run_id}'"
      ActiveRecord::Base.connection.execute(stmt)
  #  end    # uncomment to use spawn
  end

   def save_run(params)
     roles = "#{params['host_roles']}"
     $host_roles = roles.split(",") # set $host_roles
     created_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
     stmt = "INSERT INTO runs (mu_ip, host_names, host_roles, host_types, scenario_name,
             scenario_uuid, testsuite_name, testsuite_uuid, created_at, updated_at)
             values ( '#{params["mu_ip"]}',
                      '#{params["host_names"]}',
                      '#{params["host_roles"]}',
                      '#{params["host_types"]}',
                      '#{params["scenario_name"]}',
                      '#{params["scenario_uuid"]}',
                      '#{params["testsuite_name"]}',
                      '#{params["testsuite_uuid"]}',
                      '#{created_at}', '#{created_at}')"
     ActiveRecord::Base.connection.execute(stmt)
   end

   def update_run(params)
     updated_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
     stmt = "update runs
             set mu_ip = '#{params["mu_ip"]}',
             host_names = '#{params['host_names']}',
             host_types = '#{params['host_types']}',
             scenario_name = '#{params["scenario_name"]}',
             scenario_uuid = '#{params["scenario_uuid"]}',
             testsuite_name = '#{params["testsuite_name"]}',
             testsuite_uuid =  '#{params["testsuite_uuid"]}',
             updated_at = '#{updated_at}'
             where id = '#{params['run_id']}'"
     ActiveRecord::Base.connection.execute(stmt)
   end
  
end
